/**
 * Copyright 2013-2023 Software Radio Systems Limited
 *
 * This file is part of srsRAN.
 *
 * srsRAN is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * srsRAN is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * A copy of the GNU Affero General Public License can be found in
 * the LICENSE file in the top-level directory of this distribution
 * and at http://www.gnu.org/licenses/.
 *
 */

#include "../../../srsue/hdr/stack/rrc/rrc.h" // for rrc_args_t
#include "srsran/asn1/rrc/ul_dcch_msg.h"
#include "srsran/common/mac_pcap.h"
#include <iostream>

using namespace asn1;
using namespace asn1::rrc;

#define PCAP 0
#define JSON_OUTPUT 1

#define TESTASSERT(cond)                                                                                               \
  {                                                                                                                    \
    if (!(cond)) {                                                                                                     \
      std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl;              \
      return -1;                                                                                                       \
    }                                                                                                                  \
  }

int rrc_nr_test_scg_fail_packing()
{
  ul_dcch_msg_s           ul_dcch_msg;
  scg_fail_info_nr_r15_s& scg_fail_info_nr = ul_dcch_msg.msg.set_msg_class_ext().set_c2().set_scg_fail_info_nr_r15();
  scg_fail_info_nr.crit_exts.set_c1();
  scg_fail_info_nr.crit_exts.c1().set_scg_fail_info_nr_r15();

  scg_fail_info_nr.crit_exts.c1().scg_fail_info_nr_r15().fail_report_scg_nr_r15_present = true;
  scg_fail_info_nr.crit_exts.c1().scg_fail_info_nr_r15().fail_report_scg_nr_r15.fail_type_r15 =
      fail_report_scg_nr_r15_s::fail_type_r15_opts::options::scg_recfg_fail;
  uint8_t buf[64];
  bzero(buf, sizeof(buf));
  asn1::bit_ref bref(buf, sizeof(buf));
  TESTASSERT(ul_dcch_msg.pack(bref) == SRSRAN_SUCCESS);
  bref.align_bytes_zero();
  uint32_t cap_len = (uint32_t)bref.distance_bytes(buf);
  return SRSRAN_SUCCESS;
}

int rrc_ue_cap_info_test(srsran::mac_pcap* pcap)
{
  auto& rrc_logger = srslog::fetch_basic_logger("RRC", false);
  rrc_logger.set_level(srslog::basic_levels::debug);
  rrc_logger.set_hex_dump_max_size(128);

  srsue::rrc_args_t args   = {};
  args.feature_group       = 0xe6041c00;
  args.nof_supported_bands = 1;
  args.supported_bands[0]  = 8;
  args.ue_category         = 4;

  asn1::rrc::ul_dcch_msg_s ul_dcch_msg;
  ul_dcch_msg.msg.set(ul_dcch_msg_type_c::types::c1);
  ul_dcch_msg.msg.c1().set(ul_dcch_msg_type_c::c1_c_::types::ue_cap_info);
  ul_dcch_msg.msg.c1().ue_cap_info().rrc_transaction_id = 0;

  ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.set(ue_cap_info_s::crit_exts_c_::types::c1);
  ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().set(ue_cap_info_s::crit_exts_c_::c1_c_::types::ue_cap_info_r8);
  ue_cap_info_r8_ies_s* info = &ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().ue_cap_info_r8();
  info->ue_cap_rat_container_list.resize(1);
  info->ue_cap_rat_container_list[0].rat_type = rat_type_e::eutra;

  ue_eutra_cap_s cap;
  cap.access_stratum_release                            = access_stratum_release_e::rel8;
  cap.ue_category                                       = (uint8_t)args.ue_category;
  cap.pdcp_params.max_num_rohc_context_sessions_present = false;

  cap.phy_layer_params.ue_specific_ref_sigs_supported = false;
  cap.phy_layer_params.ue_tx_ant_sel_supported        = false;

  cap.rf_params.supported_band_list_eutra.resize(args.nof_supported_bands);
  cap.meas_params.band_list_eutra.resize(args.nof_supported_bands);
  for (uint32_t i = 0; i < args.nof_supported_bands; i++) {
    cap.rf_params.supported_band_list_eutra[i].band_eutra  = args.supported_bands[i];
    cap.rf_params.supported_band_list_eutra[i].half_duplex = false;
    cap.meas_params.band_list_eutra[i].inter_freq_band_list.resize(1);
    cap.meas_params.band_list_eutra[i].inter_freq_band_list[0].inter_freq_need_for_gaps = true;
  }

  cap.feature_group_inds_present = true;
  cap.feature_group_inds.from_number(args.feature_group);

  uint8_t buf[64];
  bzero(buf, sizeof(buf));
  asn1::bit_ref bref(buf, sizeof(buf));
  cap.pack(bref);
  bref.align_bytes_zero();
  uint32_t cap_len = (uint32_t)bref.distance_bytes(buf);

  info->ue_cap_rat_container_list[0].ue_cap_rat_container.resize(cap_len);
  memcpy(info->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), buf, cap_len);
  rrc_logger.debug(buf, cap_len, "UE-Cap (%d/%zd B)", cap_len, sizeof(buf));

  // pack the message
  uint8_t byte_buf[32];
  bzero(byte_buf, sizeof(byte_buf));
  asn1::bit_ref bref3(byte_buf, sizeof(byte_buf));
  ul_dcch_msg.pack(bref3);
  bref3.align_bytes_zero();

  uint32_t len = (uint32_t)bref3.distance_bytes(byte_buf);
  rrc_logger.debug(byte_buf, len, "UL-DCCH (%d/%zd B)", len, sizeof(byte_buf));

  if (pcap != NULL) {
    pcap->write_ul_rrc_pdu(byte_buf, len);
  }

  return 0;
}

int rrc_ue_cap_info_pack_buff_size_test(srsran::mac_pcap* pcap, const uint32_t buf_size)
{
  auto& rrc_logger = srslog::fetch_basic_logger("RRC", false);
  rrc_logger.set_level(srslog::basic_levels::debug);
  rrc_logger.set_hex_dump_max_size(128);

  srsue::rrc_args_t args   = {};
  args.ue_category         = 8;
  args.ue_category_ul      = 5;
  args.ue_category_dl      = 14;
  args.release             = 15;
  args.feature_group       = 0xe6041c00;
  args.nof_supported_bands = 1;
  args.supported_bands[0]  = 8;
  args.nof_lte_carriers    = 4;
  args.nof_nr_carriers     = 0;
  args.support_ca          = true;
  args.supported_bands_nr.push_back(3);

  asn1::rrc::ul_dcch_msg_s ul_dcch_msg;
  ul_dcch_msg.msg.set(ul_dcch_msg_type_c::types::c1);
  ul_dcch_msg.msg.c1().set(ul_dcch_msg_type_c::c1_c_::types::ue_cap_info);
  ul_dcch_msg.msg.c1().ue_cap_info().rrc_transaction_id = 0;

  ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.set(ue_cap_info_s::crit_exts_c_::types::c1);
  ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().set(ue_cap_info_s::crit_exts_c_::c1_c_::types::ue_cap_info_r8);
  ue_cap_info_r8_ies_s* info = &ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().ue_cap_info_r8();
  info->ue_cap_rat_container_list.resize(1);
  info->ue_cap_rat_container_list[0].rat_type = rat_type_e::eutra;

  ue_eutra_cap_s cap;
  cap.access_stratum_release = (access_stratum_release_e::options)(args.release - SRSRAN_RELEASE_MIN);
  cap.ue_category            = (uint8_t)((args.ue_category < 1 || args.ue_category > 5) ? 4 : args.ue_category);
  cap.pdcp_params.max_num_rohc_context_sessions_present     = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0001_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0002_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0003_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0004_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0006_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0101_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0102_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0103_r15 = false;
  cap.pdcp_params.supported_rohc_profiles.profile0x0104_r15 = false;

  cap.phy_layer_params.ue_specific_ref_sigs_supported = false;
  cap.phy_layer_params.ue_tx_ant_sel_supported        = false;

  cap.rf_params.supported_band_list_eutra.resize(args.nof_supported_bands);
  cap.meas_params.band_list_eutra.resize(args.nof_supported_bands);
  for (uint32_t k = 0; k < args.nof_supported_bands; k++) {
    cap.rf_params.supported_band_list_eutra[k].band_eutra  = args.supported_bands[k];
    cap.rf_params.supported_band_list_eutra[k].half_duplex = false;
    cap.meas_params.band_list_eutra[k].inter_freq_band_list.resize(1);
    cap.meas_params.band_list_eutra[k].inter_freq_band_list[0].inter_freq_need_for_gaps = true;
  }

  cap.feature_group_inds_present = true;
  cap.feature_group_inds.from_number(args.feature_group);

  ue_eutra_cap_v1280_ies_s* ue_eutra_cap_v1280_ies;
  ue_eutra_cap_v1360_ies_s* ue_eutra_cap_v1360_ies;
  ue_eutra_cap_v1450_ies_s* ue_eutra_cap_v1450_ies;
  if (args.release > 8) {
    ue_eutra_cap_v920_ies_s cap_v920;

    cap_v920.phy_layer_params_v920.enhanced_dual_layer_fdd_r9_present                        = false;
    cap_v920.phy_layer_params_v920.enhanced_dual_layer_tdd_r9_present                        = false;
    cap_v920.inter_rat_params_geran_v920.dtm_r9_present                                      = false;
    cap_v920.inter_rat_params_geran_v920.e_redirection_geran_r9_present                      = false;
    cap_v920.csg_proximity_ind_params_r9.inter_freq_proximity_ind_r9_present                 = false;
    cap_v920.csg_proximity_ind_params_r9.intra_freq_proximity_ind_r9_present                 = false;
    cap_v920.csg_proximity_ind_params_r9.utran_proximity_ind_r9_present                      = false;
    cap_v920.neigh_cell_si_acquisition_params_r9.inter_freq_si_acquisition_for_ho_r9_present = false;
    cap_v920.neigh_cell_si_acquisition_params_r9.intra_freq_si_acquisition_for_ho_r9_present = false;
    cap_v920.neigh_cell_si_acquisition_params_r9.utran_si_acquisition_for_ho_r9_present      = false;
    cap_v920.son_params_r9.rach_report_r9_present                                            = false;

    cap.non_crit_ext_present = true;
    cap.non_crit_ext         = cap_v920;
  }

  if (args.release > 9) {
    phy_layer_params_v1020_s phy_layer_params_v1020;
    phy_layer_params_v1020.two_ant_ports_for_pucch_r10_present             = false;
    phy_layer_params_v1020.tm9_with_minus8_tx_fdd_r10_present              = false;
    phy_layer_params_v1020.pmi_disabling_r10_present                       = false;
    phy_layer_params_v1020.cross_carrier_sched_r10_present                 = args.support_ca;
    phy_layer_params_v1020.simul_pucch_pusch_r10_present                   = false;
    phy_layer_params_v1020.multi_cluster_pusch_within_cc_r10_present       = false;
    phy_layer_params_v1020.non_contiguous_ul_ra_within_cc_list_r10_present = false;

    rf_params_v1020_s             rf_params;
    band_combination_params_r10_l combination_params;
    if (args.support_ca) {
      // add Intra‑band Contiguous or Inter‑band Non-contiguous CA band combination
      // note that nof_supported_bands=1 when all cells are in the same but non-contiguous band
      for (uint32_t k = 0; k < args.nof_supported_bands; k++) {
        ca_mimo_params_dl_r10_s ca_mimo_params_dl;
        ca_mimo_params_dl.ca_bw_class_dl_r10                = ca_bw_class_r10_e::f;
        ca_mimo_params_dl.supported_mimo_cap_dl_r10_present = false;

        ca_mimo_params_ul_r10_s ca_mimo_params_ul;
        ca_mimo_params_ul.ca_bw_class_ul_r10                = ca_bw_class_r10_e::f;
        ca_mimo_params_ul.supported_mimo_cap_ul_r10_present = false;

        band_params_r10_s band_params;
        band_params.band_eutra_r10             = args.supported_bands[k];
        band_params.band_params_dl_r10_present = true;
        band_params.band_params_dl_r10.push_back(ca_mimo_params_dl);
        band_params.band_params_ul_r10_present = true;
        band_params.band_params_ul_r10.push_back(ca_mimo_params_ul);

        combination_params.push_back(band_params);
      }
    }
    rf_params.supported_band_combination_r10.push_back(combination_params);

    // add all 2CC, 3CC and 4CC Intra‑band Non-contiguous CA band combinations
    for (uint32_t k = 0; k < args.nof_supported_bands; k++) {
      for (uint32_t j = 2; j <= args.nof_lte_carriers; j++) {
        combination_params.clear();

        ca_mimo_params_dl_r10_s ca_mimo_params_dl;
        ca_mimo_params_dl.ca_bw_class_dl_r10                = ca_bw_class_r10_e::a;
        ca_mimo_params_dl.supported_mimo_cap_dl_r10_present = false;

        ca_mimo_params_ul_r10_s ca_mimo_params_ul;
        ca_mimo_params_ul.ca_bw_class_ul_r10                = ca_bw_class_r10_e::a;
        ca_mimo_params_ul.supported_mimo_cap_ul_r10_present = false;

        band_params_r10_s band_params;
        band_params.band_eutra_r10             = args.supported_bands[k];
        band_params.band_params_dl_r10_present = true;
        band_params.band_params_dl_r10.push_back(ca_mimo_params_dl);
        band_params.band_params_ul_r10_present = true;
        band_params.band_params_ul_r10.push_back(ca_mimo_params_ul);

        for (uint32_t l = 0; l < j; l++) {
          combination_params.push_back(band_params);
        }
        rf_params.supported_band_combination_r10.push_back(combination_params);
      }
    }

    ue_eutra_cap_v1020_ies_s cap_v1020;
    if (args.ue_category >= 6 && args.ue_category <= 8) {
      cap_v1020.ue_category_v1020_present = true;
      cap_v1020.ue_category_v1020         = (uint8_t)args.ue_category;
    } else {
      // Do not populate UE category for this release if the category is out of range
    }
    cap_v1020.phy_layer_params_v1020_present = true;
    cap_v1020.phy_layer_params_v1020         = phy_layer_params_v1020;
    cap_v1020.rf_params_v1020_present        = args.support_ca;
    cap_v1020.rf_params_v1020                = rf_params;

    ue_eutra_cap_v940_ies_s cap_v940;
    cap_v940.non_crit_ext_present = true;
    cap_v940.non_crit_ext         = cap_v1020;

    cap.non_crit_ext.non_crit_ext_present = true;
    cap.non_crit_ext.non_crit_ext         = cap_v940;
  }

  if (args.release > 10) {
    ue_eutra_cap_v11a0_ies_s cap_v11a0;
    if (args.ue_category >= 11 && args.ue_category <= 12) {
      cap_v11a0.ue_category_v11a0         = (uint8_t)args.ue_category;
      cap_v11a0.ue_category_v11a0_present = true;
    } else {
      // Do not populate UE category for this release if the category is out of range
    }

    ue_eutra_cap_v1180_ies_s cap_v1180;
    cap_v1180.non_crit_ext_present = true;
    cap_v1180.non_crit_ext         = cap_v11a0;

    ue_eutra_cap_v1170_ies_s cap_v1170;
    cap_v1170.non_crit_ext_present = true;
    cap_v1170.non_crit_ext         = cap_v1180;
    if (args.ue_category >= 9 && args.ue_category <= 10) {
      cap_v1170.ue_category_v1170         = (uint8_t)args.ue_category;
      cap_v1170.ue_category_v1170_present = true;
    } else {
      // Do not populate UE category for this release if the category is out of range
    }

    ue_eutra_cap_v1130_ies_s cap_v1130;
    cap_v1130.non_crit_ext_present = true;
    cap_v1130.non_crit_ext         = cap_v1170;

    ue_eutra_cap_v1090_ies_s cap_v1090;
    cap_v1090.non_crit_ext_present = true;
    cap_v1090.non_crit_ext         = cap_v1130;

    ue_eutra_cap_v1060_ies_s cap_v1060;
    cap_v1060.non_crit_ext_present = true;
    cap_v1060.non_crit_ext         = cap_v1090;

    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext         = cap_v1060;
  }

  if (args.release > 11) {
    supported_band_list_eutra_v1250_l supported_band_list_eutra_v1250;
    for (uint32_t k = 0; k < args.nof_supported_bands; k++) {
      supported_band_eutra_v1250_s supported_band_eutra_v1250;
      // According to 3GPP 36.306 v12 Table 4.1A-1, 256QAM is supported for ue_category_dl 11-16
      supported_band_eutra_v1250.dl_minus256_qam_r12_present = (args.ue_category_dl >= 11);

      // According to 3GPP 36.331 v12 UE-EUTRA-Capability field descriptions
      // This field is only present when the field ue-CategoryUL is considered to 5 or 13.
      supported_band_eutra_v1250.ul_minus64_qam_r12_present = true;

      supported_band_list_eutra_v1250.push_back(supported_band_eutra_v1250);
    }

    rf_params_v1250_s rf_params_v1250;
    rf_params_v1250.supported_band_list_eutra_v1250_present = true;
    rf_params_v1250.supported_band_list_eutra_v1250         = supported_band_list_eutra_v1250;

    ue_eutra_cap_v1250_ies_s cap_v1250;

    // Optional UE Category UL/DL
    // Warning: Make sure the UE Category UL/DL matches with 3GPP 36.306 Table 4.1A-6
    if (args.ue_category_dl >= 0) {
      cap_v1250.ue_category_dl_r12_present = true;
      cap_v1250.ue_category_dl_r12         = (uint8_t)args.ue_category_dl;
    } else {
      // Do not populate UE category for this release if the category is not available
    }
    if (args.ue_category_ul >= 0) {
      cap_v1250.ue_category_ul_r12_present = true;
      cap_v1250.ue_category_ul_r12         = (uint8_t)args.ue_category_ul;
    } else {
      // Do not populate UE category for this release if the category is not available
    }
    cap_v1250.rf_params_v1250_present = true;
    cap_v1250.rf_params_v1250         = rf_params_v1250;

    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
        .non_crit_ext.non_crit_ext_present = true;
    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
        .non_crit_ext.non_crit_ext = cap_v1250;
    // 12.50
    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
        .non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    // 12.60
    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
        .non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    // 12.70
    cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
        .non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
  }
  // Release 13
  if (args.release > 12) {
    // 12.80
    ue_eutra_cap_v1280_ies =
        &cap.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
             .non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
    ue_eutra_cap_v1280_ies->non_crit_ext_present = true;
    // 13.10
    ue_eutra_cap_v1280_ies->non_crit_ext.non_crit_ext_present = true;
    // 13.20
    ue_eutra_cap_v1280_ies->non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    // 13.30
    ue_eutra_cap_v1280_ies->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    // 13.40
    ue_eutra_cap_v1280_ies->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    // 13.50
    ue_eutra_cap_v1280_ies->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present =
        true;
  }
  // Release 14
  if (args.release > 13) {
    // 13.60
    ue_eutra_cap_v1360_ies =
        &ue_eutra_cap_v1280_ies->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
    ue_eutra_cap_v1360_ies->non_crit_ext_present = true;
    // 14.30
    ue_eutra_cap_v1360_ies->non_crit_ext.non_crit_ext_present = true;
    // 14.40
    ue_eutra_cap_v1360_ies->non_crit_ext.non_crit_ext.non_crit_ext_present = true;
    // 14.50
    ue_eutra_cap_v1360_ies->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
  }
  // Release 15
  if (args.release > 14) {
    ue_eutra_cap_v1450_ies = &ue_eutra_cap_v1360_ies->non_crit_ext.non_crit_ext.non_crit_ext;
    // 14.60
    ue_eutra_cap_v1450_ies->non_crit_ext_present              = true;
    ue_eutra_cap_v1450_ies->non_crit_ext.non_crit_ext_present = true;

    irat_params_nr_r15_s irat_params_nr_r15;
    irat_params_nr_r15.en_dc_r15_present                     = true;
    irat_params_nr_r15.supported_band_list_en_dc_r15_present = true;

    uint32_t nof_supported_nr_bands = args.supported_bands_nr.size();
    irat_params_nr_r15.supported_band_list_en_dc_r15.resize(nof_supported_nr_bands);
    for (uint32_t k = 0; k < nof_supported_nr_bands; k++) {
      irat_params_nr_r15.supported_band_list_en_dc_r15[k].band_nr_r15 = args.supported_bands_nr[k];
    }

    ue_eutra_cap_v1450_ies->non_crit_ext.non_crit_ext.irat_params_nr_r15_present = true;
    ue_eutra_cap_v1450_ies->non_crit_ext.non_crit_ext.irat_params_nr_r15         = irat_params_nr_r15;
    ue_eutra_cap_v1450_ies->non_crit_ext.non_crit_ext.non_crit_ext_present       = true;

    // 15.10
    ue_eutra_cap_v1510_ies_s* ue_cap_enquiry_v1510_ies   = &ue_eutra_cap_v1450_ies->non_crit_ext.non_crit_ext;
    ue_cap_enquiry_v1510_ies->pdcp_params_nr_r15_present = true;
    ue_cap_enquiry_v1510_ies->pdcp_params_nr_r15.sn_size_lo_r15_present = true;
  }

  // Pack caps and copy to cap info
  uint8_t buf[128];
  bzero(buf, sizeof(buf));
  asn1::bit_ref bref(buf, buf_size);
  if (cap.pack(bref) != asn1::SRSASN_SUCCESS) {
    rrc_logger.debug("Error packing EUTRA capabilities");
    return -1;
  }

  bref.align_bytes_zero();
  uint32_t cap_len = (uint32_t)bref.distance_bytes(buf);

  info->ue_cap_rat_container_list[0].ue_cap_rat_container.resize(cap_len);
  memcpy(info->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), buf, cap_len);
  rrc_logger.debug(buf, cap_len, "UE-Cap (%d/%zd B)", cap_len, sizeof(buf));

  // pack the message
  uint8_t byte_buf[512];
  bzero(byte_buf, sizeof(byte_buf));
  asn1::bit_ref bref3(byte_buf, sizeof(byte_buf));
  ul_dcch_msg.pack(bref3);
  bref3.align_bytes_zero();

  uint32_t len = (uint32_t)bref3.distance_bytes(byte_buf);
  rrc_logger.debug(byte_buf, len, "UL-DCCH (%d/%zd B)", len, sizeof(byte_buf));

  if (pcap != NULL) {
    pcap->write_ul_rrc_pdu(byte_buf, len);
  }

  return 0;
}

int pack_fail_test()
{
  srsue::rrc_args_t args   = {};
  args.feature_group       = 0xe6041c00;
  args.nof_supported_bands = 1;
  args.supported_bands[0]  = 8;
  args.ue_category         = 4;

  asn1::rrc::ul_dcch_msg_s ul_dcch_msg;
  ul_dcch_msg.msg.set(ul_dcch_msg_type_c::types::c1);
  ul_dcch_msg.msg.c1().set(ul_dcch_msg_type_c::c1_c_::types::ue_cap_info);
  ul_dcch_msg.msg.c1().ue_cap_info().rrc_transaction_id = 0;

  ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.set(ue_cap_info_s::crit_exts_c_::types::c1);
  ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().set(ue_cap_info_s::crit_exts_c_::c1_c_::types::ue_cap_info_r8);
  ue_cap_info_r8_ies_s* info = &ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().ue_cap_info_r8();
  info->ue_cap_rat_container_list.resize(1);
  info->ue_cap_rat_container_list[0].rat_type = rat_type_e::eutra;

  ue_eutra_cap_s cap;
  cap.access_stratum_release                            = access_stratum_release_e::rel8;
  cap.ue_category                                       = (uint8_t)args.ue_category;
  cap.pdcp_params.max_num_rohc_context_sessions_present = false;

  cap.phy_layer_params.ue_specific_ref_sigs_supported = false;
  cap.phy_layer_params.ue_tx_ant_sel_supported        = false;

  cap.rf_params.supported_band_list_eutra.resize(args.nof_supported_bands);
  cap.meas_params.band_list_eutra.resize(args.nof_supported_bands);
  for (uint32_t i = 0; i < args.nof_supported_bands; i++) {
    cap.rf_params.supported_band_list_eutra[i].band_eutra  = args.supported_bands[i];
    cap.rf_params.supported_band_list_eutra[i].half_duplex = false;
    cap.meas_params.band_list_eutra[i].inter_freq_band_list.resize(1);
    cap.meas_params.band_list_eutra[i].inter_freq_band_list[0].inter_freq_need_for_gaps = true;
  }

  cap.feature_group_inds_present = true;
  cap.feature_group_inds.from_number(args.feature_group);

  uint8_t       buff[3];
  asn1::bit_ref bref(buff, sizeof(buff));
  if (ul_dcch_msg.pack(bref) != asn1::SRSASN_SUCCESS) {
    fprintf(stderr, "Error while packing message.\n");
    return -1;
  }

  return 0;
}

int rrc_ue_cap_information_test()
{
  uint8_t rrc_msg[] = {
      0x38, 0x01, 0x08, 0x89, 0x9e, 0x01, 0xb8, 0x05, 0x18, 0x18, 0x01, 0x33, 0xe6, 0xc0, 0x82, 0x06, 0x10, 0x38, 0xb1,
      0x84, 0x08, 0x92, 0x30, 0x65, 0x2a, 0x64, 0xea, 0x14, 0xaa, 0x5e, 0xfc, 0xc1, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff,
      0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f,
      0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9,
      0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff,
      0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff,
      0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xf9, 0x8f, 0xff, 0xff, 0xfb, 0xf0,
      0x6e, 0xc4, 0xf0, 0x01, 0x41, 0xbc, 0x05, 0xdc, 0x80, 0x00, 0x00, 0x00, 0x2f, 0x60, 0x00, 0x00, 0x02, 0x02, 0x77,
      0xc0, 0x00, 0x00, 0x00, 0xbf, 0xf0, 0x03, 0x00, 0x21, 0x00, 0x30, 0x02, 0x00, 0x80, 0x14, 0x00, 0xc0, 0x0c, 0x00,
      0x90, 0x03, 0x04, 0x21, 0x80, 0x18, 0x01, 0x82, 0x10, 0xc1, 0x08, 0x60, 0x80, 0x30, 0x40, 0x18, 0x20, 0x0c, 0x10,
      0x86, 0x08, 0x43, 0x04, 0x21, 0x82, 0x10, 0xc1, 0x00, 0x60, 0x80, 0x24, 0x10, 0x06, 0x08, 0x03, 0x04, 0x20, 0x82,
      0x10, 0x41, 0x08, 0x60, 0x84, 0x30, 0x42, 0x18, 0x21, 0x0c, 0x10, 0x82, 0x08, 0x41, 0x04, 0x21, 0x41, 0x00, 0x60,
      0x80, 0x30, 0x40, 0x12, 0x08, 0x43, 0x04, 0x21, 0x82, 0x10, 0xc1, 0x08, 0x60, 0x84, 0x30, 0x42, 0x18, 0x20, 0x0c,
      0x10, 0x04, 0x20, 0x80, 0x30, 0x40, 0x18, 0x20, 0x0c, 0x10, 0x06, 0x08, 0x43, 0x04, 0x21, 0x41, 0x08, 0x20, 0x84,
      0x10, 0x42, 0x08, 0x21, 0x04, 0x10, 0x06, 0x08, 0x02, 0x41, 0x00, 0x40, 0x82, 0x00, 0xc1, 0x00, 0x60, 0x80, 0x30,
      0x40, 0x12, 0x08, 0x41, 0x04, 0x20, 0x02, 0x08, 0x41, 0x04, 0x20, 0x20, 0x84, 0x30, 0x42, 0x18, 0x21, 0x0c, 0x10,
      0x86, 0x08, 0x43, 0x04, 0x21, 0x08, 0x20, 0x0c, 0x10, 0x06, 0x08, 0x03, 0x04, 0x01, 0x82, 0x10, 0xc0, 0x0c, 0x30,
      0x84, 0x21, 0x80, 0x12, 0xd7, 0xd5, 0x46, 0xc0, 0x3c, 0x00, 0x03, 0xf8, 0x18, 0xc0, 0x00, 0x82, 0x06, 0x00, 0x00,
      0x20, 0x81, 0xa6, 0x00, 0x08, 0x00, 0x2f, 0x84, 0x00, 0x36, 0xc0, 0x01, 0x00, 0x0c, 0x10, 0x00, 0x40, 0x03, 0x08,
      0x00, 0x10, 0x40, 0xc3, 0x00, 0x04, 0x10, 0x31, 0x00, 0x01, 0x00, 0x0c, 0x70, 0x00, 0x40, 0x03, 0x2c, 0x00, 0x10,
      0x00, 0xcc, 0x00, 0x04, 0x00, 0x34, 0x00, 0x01, 0x00, 0x0d, 0x10, 0x00, 0x40, 0x03, 0x48, 0x00, 0x10, 0x00, 0xd8,
      0x00, 0x04, 0x00, 0x36, 0x40, 0x01, 0x00, 0x0e, 0x50, 0x00, 0x41, 0x03, 0x98, 0x00, 0x10, 0x00, 0xe7, 0x00, 0x04,
      0x10, 0x3a, 0x00, 0x01, 0x04, 0x0e, 0x90, 0x00, 0x41, 0x03, 0xa8, 0x00, 0x10, 0x00, 0xef, 0x00, 0x04, 0x00, 0x3f,
      0xc0, 0x01, 0x04, 0x1c, 0x60, 0x00, 0x41, 0x46, 0x08, 0x20, 0x63, 0x00, 0x02, 0x48, 0x18, 0xc0, 0x00, 0x8a, 0x0e,
      0x30, 0x00, 0x20, 0xa0, 0x04, 0x10, 0x51, 0x82, 0x0e, 0x00, 0x00, 0x20, 0x83, 0xa6, 0x00, 0x08, 0x08, 0xc1, 0x04,
      0x15, 0x30, 0x81, 0x8c, 0x00, 0x08, 0x20, 0xaf, 0x84, 0x0c, 0x60, 0x00, 0x41, 0x07, 0xfc, 0x00, 0x10, 0x51, 0x82,
      0x08, 0x2f, 0xe1, 0x07, 0x18, 0x00, 0x10, 0x41, 0xe9, 0x00, 0x04, 0x14, 0x60, 0x82, 0x0b, 0x48, 0x41, 0xc6, 0x00,
      0x04, 0x10, 0x76, 0xc0, 0x01, 0x01, 0x18, 0x20, 0x82, 0xb6, 0x10, 0x31, 0x80, 0x01, 0x04, 0x1d, 0x90, 0x00, 0x40,
      0x46, 0x08, 0x00, 0xac, 0x84, 0x0c, 0x60, 0x00, 0x40, 0x07, 0x1c, 0x00, 0x10, 0x11, 0x82, 0x08, 0x28, 0xe1, 0x03,
      0x18, 0x00, 0x10, 0x41, 0xc6, 0x00, 0x04, 0x14, 0x40, 0x80, 0x0a, 0x30, 0x41, 0xc4, 0x00, 0x04, 0x00, 0x71, 0x80,
      0x01, 0x05, 0x0c, 0x20, 0x82, 0x8c, 0x10, 0x70, 0xc0, 0x01, 0x04, 0x1c, 0x60, 0x00, 0x41, 0x42, 0x08, 0x20, 0xa3,
      0x04, 0x1c, 0x20, 0x00, 0x41, 0x07, 0x18, 0x00, 0x10, 0x50, 0x42, 0x00, 0x28, 0xc1, 0x07, 0x04, 0x00, 0x10, 0x01,
      0xc0, 0x00, 0x04, 0x14, 0x00, 0x82, 0x06, 0x00, 0x00, 0x24, 0x03, 0xa6, 0x00, 0x08, 0x08, 0x01, 0x04, 0x15, 0x30,
      0x81, 0x80, 0x00, 0x08, 0x20, 0xaf, 0x84, 0x0c, 0x00, 0x00, 0x41, 0x07, 0xa4, 0x00, 0x10, 0x10, 0x02, 0x00, 0x2d,
      0x21, 0x03, 0x00, 0x00, 0x10, 0x01, 0xe8, 0x00, 0x04, 0x14, 0x00, 0x82, 0x0b, 0x40, 0x41, 0xc0, 0x00, 0x04, 0x10,
      0x79, 0xc0, 0x01, 0x05, 0x00, 0x20, 0x82, 0xce, 0x10, 0x70, 0x00, 0x01, 0x04, 0x1e, 0x50, 0x00, 0x41, 0x40, 0x08,
      0x20, 0xb2, 0x84, 0x1c, 0x00, 0x00, 0x41, 0x07, 0x6c, 0x00, 0x10, 0x10, 0x02, 0x08, 0x2b, 0x61, 0x03, 0x00, 0x00,
      0x10, 0x41, 0xd2, 0x00, 0x04, 0x04, 0x00, 0x80, 0x0a, 0x90, 0x40, 0xc0, 0x00, 0x04, 0x00, 0x74, 0x40, 0x01, 0x01,
      0x00, 0x20, 0x02, 0xa2, 0x10, 0x30, 0x00, 0x01, 0x00, 0x1c, 0x70, 0x00, 0x40, 0x40, 0x08, 0x20, 0xa3, 0x84, 0x0c,
      0x00, 0x00, 0x41, 0x07, 0x10, 0x00, 0x10, 0x10, 0x02, 0x08, 0x28, 0x81, 0x03, 0x00, 0x00, 0x10, 0x41, 0xc2, 0x00,
      0x04, 0x14, 0x00, 0x82, 0x0a, 0x10, 0x41, 0xc0, 0x00, 0x04, 0x10, 0x57, 0xc2, 0x06, 0x98, 0x00, 0x20, 0x03, 0xce,
      0x00, 0x08, 0x2a, 0x61, 0x00, 0x16, 0x70, 0x83, 0xa6, 0x00, 0x08, 0x00, 0xf2, 0x80, 0x02, 0x0a, 0x98, 0x40, 0x05,
      0x94, 0x20, 0xe9, 0x80, 0x02, 0x00, 0x3a, 0x60, 0x00, 0x80, 0x84, 0x10, 0x41, 0x53, 0x08, 0x18, 0x40, 0x00, 0x82,
      0x0a, 0xf8, 0x40, 0xdb, 0x00, 0x04, 0x00, 0x57, 0xc2, 0x06, 0x38, 0x00, 0x20, 0x02, 0xbe, 0x10, 0x30, 0x80, 0x01,
      0x04, 0x1e, 0x90, 0x00, 0x40, 0x5b, 0x08, 0x00, 0xb4, 0x84, 0x0d, 0xb0, 0x00, 0x40, 0x07, 0xa0, 0x00, 0x10, 0x16,
      0xc2, 0x00, 0x2d, 0x01, 0x03, 0x6c, 0x00, 0x10, 0x01, 0xe5, 0x00, 0x04, 0x05, 0xb0, 0x80, 0x0b, 0x28, 0x40, 0xdb,
      0x00, 0x04, 0x00, 0x76, 0xc0, 0x01, 0x01, 0x0c, 0x20, 0x82, 0xb6, 0x10, 0x30, 0xc0, 0x01, 0x04, 0x1d, 0xb0, 0x00,
      0x40, 0x42, 0x08, 0x20, 0xad, 0x84, 0x0c, 0x20, 0x00, 0x41, 0x07, 0x6c, 0x00, 0x10, 0x10, 0x42, 0x00, 0x2b, 0x61,
      0x03, 0x04, 0x00, 0x10, 0x01, 0xff, 0x00, 0x04, 0x14, 0x10, 0x80, 0x0b, 0xf8, 0x41, 0xc1, 0x00, 0x04, 0x00, 0x74,
      0x00, 0x01, 0x01, 0x04, 0x20, 0x02, 0xa0, 0x10, 0x30, 0x40, 0x01, 0x00, 0x1c, 0xb0, 0x00, 0x40, 0x41, 0x08, 0x00,
      0xa5, 0x84, 0x0c, 0x10, 0x00, 0x40, 0x07, 0x10, 0x00, 0x10, 0x10, 0x42, 0x00, 0x28, 0x81, 0x03, 0x04, 0x00, 0x10,
      0x01, 0xc3, 0x00, 0x04, 0x14, 0x10, 0x80, 0x0a, 0x18, 0x41, 0xc1, 0x00, 0x04, 0x00, 0x7a, 0x40, 0x01, 0x01, 0x08,
      0x20, 0x02, 0xd2, 0x10, 0x30, 0x80, 0x01, 0x00, 0x1e, 0x80, 0x00, 0x41, 0x42, 0x08, 0x20, 0xb4, 0x04, 0x1c, 0x20,
      0x00, 0x41, 0x07, 0x9c, 0x00, 0x10, 0x50, 0x82, 0x08, 0x2c, 0xe1, 0x07, 0x08, 0x00, 0x10, 0x41, 0xe5, 0x00, 0x04,
      0x14, 0x20, 0x82, 0x0b, 0x28, 0x41, 0xc2, 0x00, 0x04, 0x10, 0x74, 0x80, 0x01, 0x01, 0x08, 0x20, 0x02, 0xa4, 0x10,
      0x30, 0x80, 0x01, 0x00, 0x1d, 0x10, 0x00, 0x40, 0x42, 0x08, 0x00, 0xa8, 0x84, 0x0c, 0x20, 0x00, 0x40, 0x07, 0x1c,
      0x00, 0x10, 0x10, 0x82, 0x08, 0x28, 0xe1, 0x03, 0x08, 0x00, 0x10, 0x41, 0xc4, 0x00, 0x04, 0x04, 0x20, 0x82, 0x0a,
      0x20, 0x40, 0xc2, 0x00, 0x04, 0x10, 0x70, 0x80, 0x01, 0x05, 0x08, 0x20, 0x81, 0x84, 0x00, 0x09, 0x21, 0xb2, 0x84,
      0x14, 0x60, 0x83, 0x84, 0x00, 0x09, 0x28, 0x01, 0x04, 0x0c, 0x60, 0x10, 0x49, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff,
      0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff,
      0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff,
      0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff,
      0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff,
      0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff,
      0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63,
      0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe,
      0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff,
      0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0x63, 0xff, 0xff, 0xfe, 0xf9, 0xc0, 0x00, 0x01, 0xfb, 0x10,
      0x3e, 0x74, 0x00, 0x00, 0x11, 0xf3, 0x80, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x02, 0x3f, 0x8b, 0xa1, 0xe1, 0xe2, 0xf1,
      0x70, 0x43, 0xc3, 0x91, 0x78, 0xbc, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x38, 0x87, 0x04, 0x3c, 0x38, 0x43, 0xc3, 0x90,
      0xf0, 0xf1, 0x78, 0xbc, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x39, 0x0f, 0x0e, 0x08, 0x78, 0x70, 0x87, 0x87, 0x22,
      0xf1, 0x72, 0x2f, 0x17, 0x87, 0x87, 0x8b, 0xc5, 0xc8, 0x78, 0x78, 0x78, 0x70, 0x23, 0xf8, 0xfe, 0x4f, 0xc9, 0xf8,
      0xb9, 0x17, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x41, 0x00, 0x00, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00,
      0x40, 0x14, 0x04, 0x05, 0x01, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10,
      0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00,
      0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01,
      0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04,
      0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x14, 0x04, 0x05, 0x01, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00,
      0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01,
      0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x3c, 0x08, 0x02, 0x48, 0x07, 0x8c, 0xbc, 0xd0, 0x30, 0x1a,
      0x58, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x4a, 0x5d, 0xe3, 0x80, 0x74, 0x00, 0x2c, 0x10, 0x00, 0xcd, 0x25,
      0x08, 0x00, 0x80, 0x01, 0x2c, 0x3f, 0xc0, 0x12, 0x00, 0x90, 0x04, 0x10, 0x04, 0x80, 0x24, 0x01, 0x20, 0x09, 0x00,
      0x48, 0x02, 0x40, 0x12, 0x00, 0x90, 0x04, 0x80, 0x24, 0x01, 0x20, 0x09, 0x00, 0x48, 0x02, 0x40, 0x12, 0x00, 0x90,
      0x04, 0x80, 0x24, 0x01, 0x20, 0x09, 0x00, 0x48, 0x0a, 0x04, 0x01, 0x20, 0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50,
      0x20, 0x20, 0x90, 0x10, 0x48, 0x0a, 0x04, 0x04, 0x12, 0x02, 0x81, 0x01, 0x04, 0x80, 0xa0, 0x40, 0x41, 0x20, 0x28,
      0x10, 0x10, 0x48, 0x0a, 0x04, 0x04, 0x12, 0x02, 0x81, 0x01, 0x04, 0x80, 0xa0, 0x40, 0x41, 0x20, 0x28, 0x10, 0x10,
      0x48, 0x0a, 0x04, 0x04, 0x12, 0x02, 0x81, 0x00, 0x48, 0x0a, 0x04, 0x04, 0x12, 0x02, 0x09, 0x01, 0x40, 0x80, 0x82,
      0x40, 0x50, 0x20, 0x20, 0x90, 0x14, 0x08, 0x08, 0x24, 0x05, 0x02, 0x02, 0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50,
      0x20, 0x20, 0x90, 0x14, 0x08, 0x08, 0x24, 0x05, 0x02, 0x02, 0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50, 0x20, 0x20,
      0x90, 0x10, 0x48, 0x0a, 0x04, 0x04, 0x12, 0x02, 0x81, 0x01, 0x04, 0x80, 0xa0, 0x40, 0x41, 0x20, 0x20, 0x90, 0x10,
      0x48, 0x08, 0x24, 0x05, 0x02, 0x02, 0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50, 0x20, 0x20, 0x90, 0x14, 0x08, 0x08,
      0x24, 0x05, 0x02, 0x02, 0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50, 0x20, 0x20, 0x90, 0x14, 0x08, 0x08, 0x24, 0x05,
      0x02, 0x02, 0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50, 0x20, 0x20, 0x90, 0x14, 0x08, 0x08, 0x24, 0x05, 0x02, 0x02,
      0x09, 0x01, 0x40, 0x80, 0x82, 0x40, 0x50, 0x20, 0x20, 0x90, 0x14, 0x08, 0x08, 0x24, 0x05, 0x02, 0x02, 0x09, 0x01,
      0x40, 0x80, 0x82, 0x40, 0x50, 0x20, 0x20, 0x90, 0x14, 0x08, 0x02, 0x40, 0xc0, 0x10, 0x20, 0x04, 0x0c, 0x43, 0x2a,
      0x78, 0x18, 0x00, 0x00, 0x40, 0x20, 0x0c, 0x03, 0x82, 0x60, 0xd8, 0x4a, 0x13, 0x85, 0x02, 0x08, 0x98, 0x26, 0x88,
      0x00, 0x44, 0x02, 0x0a, 0x18, 0x32, 0xc0, 0x80, 0x00, 0x02, 0x01, 0x80, 0x70, 0x4c, 0x1b, 0x09, 0x42, 0x71, 0x36,
      0x90, 0x00};

  cbit_ref bref(rrc_msg, sizeof(rrc_msg));

  ul_dcch_msg_s ul_dcch_msg;
  TESTASSERT(ul_dcch_msg.unpack(bref) == SRSASN_SUCCESS);

  TESTASSERT(ul_dcch_msg.msg.type() == ul_dcch_msg_type_c::types::c1);
  TESTASSERT(ul_dcch_msg.msg.c1().type() == ul_dcch_msg_type_c::c1_c_::types::ue_cap_info);

  // assign to stack-allocated variable
  asn1::rrc::ue_cap_info_s ue_cap;
  ue_cap = ul_dcch_msg.msg.c1().ue_cap_info();

  TESTASSERT(ue_cap.crit_exts.c1().type() == asn1::rrc::ue_cap_info_s::crit_exts_c_::c1_c_::types::ue_cap_info_r8);
  TESTASSERT(ue_cap.crit_exts.c1().ue_cap_info_r8().ue_cap_rat_container_list.size() == 1);
  TESTASSERT(ue_cap.crit_exts.c1().ue_cap_info_r8().ue_cap_rat_container_list[0].rat_type ==
             asn1::rrc::rat_type_e::eutra);

  asn1::rrc::ue_eutra_cap_s eutra_capabilities;
  asn1::cbit_ref bref2(ue_cap.crit_exts.c1().ue_cap_info_r8().ue_cap_rat_container_list[0].ue_cap_rat_container.data(),
                       ue_cap.crit_exts.c1().ue_cap_info_r8().ue_cap_rat_container_list[0].ue_cap_rat_container.size());
  TESTASSERT(eutra_capabilities.unpack(bref2) == asn1::SRSASN_SUCCESS);

#if JSON_OUTPUT
  int               unpacked_len = bref2.distance_bytes();
  asn1::json_writer json_writer1;
  eutra_capabilities.to_json(json_writer1);
  srslog::fetch_basic_logger("ASN1").info(
      rrc_msg, sizeof(rrc_msg), "UE cap info unpacked (%d B): \n %s", unpacked_len, json_writer1.to_string().c_str());
#endif

  return 0;
}

int main(int argc, char** argv)
{
  auto& asn1_logger = srslog::fetch_basic_logger("ASN1", false);
  asn1_logger.set_level(srslog::basic_levels::debug);
  asn1_logger.set_hex_dump_max_size(-1);

  srslog::init();

#if PCAP
  srsran::mac_pcap pcap;
  pcap.open("ul_dcch.pcap");
  TESTASSERT(rrc_ue_cap_info_test(&pcap) == 0);
  TESTASSERT(rrc_ue_cap_info_pack_buff_size_test(&pcap, 64) == -1);
  TESTASSERT(rrc_ue_cap_info_pack_buff_size_test(&pcap, 128) == 0);
#else
  // TESTASSERT(rrc_ue_cap_info_test(NULL) == 0);
  TESTASSERT(rrc_ue_cap_info_pack_buff_size_test(NULL, 64) == -1);
  TESTASSERT(rrc_ue_cap_info_pack_buff_size_test(NULL, 128) == 0);
#endif
  TESTASSERT(pack_fail_test() == -1);
  TESTASSERT(rrc_nr_test_scg_fail_packing() == SRSRAN_SUCCESS)
  TESTASSERT(rrc_ue_cap_information_test() == 0);

#if PCAP
  pcap.close();
#endif
  return 0;
}
